package com.gitee.wsl.time.chinese

import com.gitee.wsl.time.chinese.util.SolarUtil.getDaysInYear
import com.gitee.wsl.time.chinese.util.SolarUtil.getDaysOfMonth
import com.gitee.wsl.time.chinese.util.SolarUtil.getWeeksOfMonth
import com.gitee.wsl.time.now
import kotlinx.datetime.LocalDate
import kotlin.math.ceil


/**
 * 阳历周
 *
 * @author 6tail
 */
class SolarWeek {
    /**
     * 获取年
     *
     * @return 年
     */
    /**
     * 年
     */
    val year: Int

    /**
     * 获取月
     *
     * @return 1到12
     */
    /**
     * 月
     */
    val month: Int

    /**
     * 获取日期
     *
     * @return 1到31之间的数字
     */
    /**
     * 日
     */
    val day: Int

    /**
     * 获取星期几作为一周的开始，1234560分别代表星期一至星期天
     *
     * @return 1234560分别代表星期一至星期天
     */
    /**
     * 星期几作为一周的开始，1234560分别代表星期一至星期天
     */
    val start: Int

    /**
     * 默认当月
     *
     * @param start 星期几作为一周的开始，1234560分别代表星期一至星期天
     */
    constructor(start: Int) : this(LocalDate.now(), start)

    /**
     * 通过日期初始化
     *
     * @param start 星期几作为一周的开始，1234560分别代表星期一至星期天
     */
    constructor(date: LocalDate, start: Int) {
        val solar: Solar = Solar.fromDate(date)
        year = solar.year
        month = solar.month
        day = solar.day
        this.start = start
    }

    /**
     * 通过年月初始化
     *
     * @param year  年
     * @param month 月，1到12
     * @param day   日，1到31
     * @param start 星期几作为一周的开始，1234560分别代表星期一至星期天
     */
    constructor(year: Int, month: Int, day: Int, start: Int) {
        this.year = year
        this.month = month
        this.day = day
        this.start = start
    }

    val index: Int
        /**
         * 获取当前日期是在当月第几周
         *
         * @return 周序号，从1开始
         */
        get() {
            var offset: Int = Solar.fromYmd(year, month, 1).week - start
            if (offset < 0) {
                offset += 7
            }
            return ceil((day + offset) / 7.0).toInt()
        }

    val indexInYear: Int
        /**
         * 获取当前日期是在当年第几周
         *
         * @return 周序号，从1开始
         */
        get() {
            var offset: Int = Solar.fromYmd(year, 1, 1).week - start
            if (offset < 0) {
                offset += 7
            }
            return ceil((getDaysInYear(year, month, day) + offset) / 7.0).toInt()
        }

    /**
     * 周推移
     *
     * @param weeks         推移的周数，负数为倒推
     * @param separateMonth 是否按月单独计算
     * @return 推移后的阳历周
     */
    fun next(weeks: Int, separateMonth: Boolean): SolarWeek {
        if (0 == weeks) {
            return SolarWeek(year, month, day, start)
        }
        var solar = Solar.fromYmd(year, month, day)
        if (separateMonth) {
            var n = weeks
            var week = SolarWeek(solar.year, solar.month, solar.day, start)
            var month = this.month
            val plus = n > 0
            while (0 != n) {
                solar = solar.next(if (plus) 7 else -7)
                week = SolarWeek(solar.year, solar.month, solar.day, start)
                var weekMonth = week.month
                if (month != weekMonth) {
                    val index = week.index
                    if (plus) {
                        if (1 == index) {
                            val firstDay = week.firstDay
                            week = SolarWeek(firstDay.year, firstDay.month, firstDay.day, start)
                            weekMonth = week.month
                        } else {
                            solar = Solar.fromYmd(week.year, week.month, 1)
                            week = SolarWeek(solar.year, solar.month, solar.day, start)
                        }
                    } else {
                        if (getWeeksOfMonth(week.year, week.month, start) == index) {
                            val lastDay = week.firstDay.next(6)
                            week = SolarWeek(lastDay.year, lastDay.month, lastDay.day, start)
                            weekMonth = week.month
                        } else {
                            solar = Solar.fromYmd(week.year, week.month, getDaysOfMonth(week.year, week.month))
                            week = SolarWeek(solar.year, solar.month, solar.day, start)
                        }
                    }
                    month = weekMonth
                }
                n -= if (plus) 1 else -1
            }
            return week
        } else {
            solar = solar.next(weeks * 7)
            return SolarWeek(solar.year, solar.month, solar.day, start)
        }
    }

    val firstDay: Solar
        /**
         * 获取本周第一天的阳历日期（可能跨月）
         *
         * @return 本周第一天的阳历日期
         */
        get() {
            val solar = Solar.fromYmd(year, month, day)
            var prev = solar.week - start
            if (prev < 0) {
                prev += 7
            }
            return solar.next(-prev)
        }

    val firstDayInMonth: Solar?
        /**
         * 获取本周第一天的阳历日期（仅限当月）
         *
         * @return 本周第一天的阳历日期
         */
        get() {
            val days = this.days
            for (day in days) {
                if (month == day.month) {
                    return day
                }
            }
            return null
        }

    val days: List<Solar>
        /**
         * 获取本周的阳历日期列表（可能跨月）
         *
         * @return 本周的阳历日期列表
         */
        get() {
            val firstDay = this.firstDay
            val l= ArrayList<Solar>()
            l.add(firstDay)
            for (i in 1..6) {
                l.add(firstDay.next(i))
            }
            return l
        }

    val daysInMonth: List<Solar>
        /**
         * 获取本周的阳历日期列表（仅限当月）
         *
         * @return 本周的阳历日期列表（仅限当月）
         */
        get() {
            val days = this.days
            val l = ArrayList<Solar>()
            for (day in days) {
                if (month != day!!.month) {
                    continue
                }
                l.add(day)
            }
            return l
        }

    override fun toString(): String {
        return year.toString() + "." + month + "." + this.index
    }

    fun toFullString(): String {
        return year.toString() + "年" + month + "月第" + this.index + "周"
    }

    companion object {
        /**
         * 通过指定日期获取阳历周
         *
         * @param date  日期
         * @param start 星期几作为一周的开始，1234560分别代表星期一至星期天
         * @return 阳历周
         */
        fun fromDate(date: LocalDate, start: Int): SolarWeek {
            return SolarWeek(date, start)
        }

        /**
         * 通过指定年月日获取阳历周
         *
         * @param year  年
         * @param month 月，1到12
         * @param day   日，1到31
         * @param start 星期几作为一周的开始，1234560分别代表星期一至星期天
         * @return 阳历周
         */
        fun fromYmd(year: Int, month: Int, day: Int, start: Int): SolarWeek {
            return SolarWeek(year, month, day, start)
        }
    }
}
